package com.tjs.lucky.domain.strategy.service.algo;

import com.tjs.lucky.common.StrategyMode;
import com.tjs.lucky.domain.strategy.model.vo.AwardRateVO;
import com.tjs.lucky.domain.strategy.model.vo.StrategyDetailBriefVO;
import com.tjs.lucky.domain.strategy.repository.IStrategyRepository;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author: 田佳澍
 * @Description: 公用的算法逻辑
 * @DateTime: 2023/5/16 13:58
 **/
public abstract class BaseAlgorithm implements IDrawAlgorithm{

    @Resource
    private IStrategyRepository strategyRepository;

    // 斐波那契散列增量，逻辑：黄金分割点：(√5 - 1) / 2 = 0.6180339887，Math.pow(2, 32) * 0.6180339887 = 0x61c88647
    private final int HASH_INCREMENT = 0x61c88647;

    // 数组初始化长度
    private final int RATE_TUPLE_LENGTH = 128;

    // 存放   策略  与   奖品对应的散列结果的对应关系，Key:策略ID Value:概率元组
    protected volatile Map<Long, String[]> rateTupleMap = new WeakHashMap<>();

    /*
        保存  策略  和  奖品信息的对应关系。Key:策略ID Value: 该策略下奖品信息（包括名称，概率）
        例如：{
                100001=
                    [AwardRateInfo(awardId=一等奖：IMac, awardRate=0.05),
                    AwardRateInfo(awardId=二等奖：iphone, awardRate=0.15),
                    AwardRateInfo(awardId=三等奖：ipad, awardRate=0.20),
                    AwardRateInfo(awardId=四等奖：AirPods, awardRate=0.25),
                    AwardRateInfo(awardId=五等奖：充电宝, awardRate=0.35)],
                ....
            }
     */
    protected volatile Map<Long, List<AwardRateVO>> awardRateInfoMap = new WeakHashMap<>();

    public String[] getFromRateTupleMap(Long strategyId){
        String[] rateTuple = rateTupleMap.get(strategyId);
        if(Objects.isNull(rateTuple) || rateTuple.length == 0){
            /*
                synchronized (strategyId){} Synchronization on local variable or method parameter
                使用 intern() 是保证String对象是 堆内存中的字符串常量池的，如果不是，可能会是不同对象，因而出现线程不安全。
             */
            synchronized (String.valueOf(strategyId).intern()){
                if(Objects.isNull(rateTuple)){
                    List<AwardRateVO> awardRateInfoList = strategyRepository.queryStrategyDetailList(strategyId);
                    rateTuple = rateTupleMap.computeIfAbsent(strategyId, k -> new String[RATE_TUPLE_LENGTH]);
                    int cursorVal = 0;
                    for (AwardRateVO awardRateInfo : awardRateInfoList) {
                        int rateVal = awardRateInfo.getAwardRate().multiply(new BigDecimal(100)).intValue();

                        // 循环填充概率范围值
                        for (int i = cursorVal + 1; i <= (rateVal + cursorVal); i++) {
                            rateTuple[hashIdx(i)] = awardRateInfo.getAwardId();
                        }
                        cursorVal += rateVal;
                    }
                    return rateTuple;
                }
            }
        }
        return rateTuple;
    }

    public List<AwardRateVO> getFromAwardRateInfoMap(Long strategyId){
        List<AwardRateVO> awardRateList = awardRateInfoMap.get(strategyId);
        if(Objects.isNull(awardRateList) || awardRateList.isEmpty()){
            synchronized (String.valueOf(strategyId).intern()){
                if(Objects.isNull(awardRateList) || awardRateList.isEmpty()){
                    awardRateList = strategyRepository.queryStrategyDetailList(strategyId);
                    awardRateInfoMap.put(strategyId, awardRateList);
                    return awardRateList;
                }
            }
        }
        return awardRateList;
    }
    /**
     * 斐波那契（Fibonacci）散列法，计算哈希索引下标值
     *
     * @param val 值
     * @return 索引
     */
    protected int hashIdx(int val) {
        int hashCode = val * HASH_INCREMENT + HASH_INCREMENT;
        return hashCode & (RATE_TUPLE_LENGTH - 1);
    }

}
